/**
 * Herbs
 * version 0.0.1
 * 
 * Class:DataSocket
 * A decorator of the flash socket that handles socket data connections
 * 
 * Copyright (c) 2011 herbless.net
 * 
 * Herbs permits you to use, modify, and distribute this file
 * in accordance with the terms of the license agreement accompanying it.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **/
package com.sailorless.net 
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	
	public class DataSocket 
	{
		public static const FLAG_CLOSE:int = 0;
		public static const FLAG_IOERROR:int = 1;
		public static const FLAG_SECURITYERROR:int = 2;
		
		protected var socket:Socket;						//basic socket
		protected var __isConnecting:Boolean = false;		//the socket is connecting?
		
		/**
		 * constructor 
		 * Constructs the data socket
		 */
		public function DataSocket() 
		{	
			
		}
		
		/**
		 * connect this socket to another socket on server.
		 * this will be fail if the socket is connecting or is already connected. 
		 * @param	host	the name or ip address of the host
		 * @param	port	the port number
		 */
		public function connect(host:String, port:int):Boolean 
		{
			//if the socket is null, create it and register the event listener
			if (socket == null)
			{
				socket = new Socket();
				socket.addEventListener(Event.CONNECT, onConnected);
				socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
				socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketReceived);
				socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
				socket.addEventListener(Event.CLOSE, onClosed);
			}
			
			if (__isConnecting || isConnected)
				return false;
				
			__isConnecting = true;
			socket.connect(host, port);
			return true;
		}
	
		/**
		 * Attempts to send data.
		 * this will be fail if the socket is not connected
		 * @param	data
		 */
		public function send(data:ByteArray):Boolean 
		{
			if (!isConnected && __isConnecting)
				return false;
			
			socket.writeBytes(data);
			socket.flush();
			return true;
		}
		
		/**
		 * close the socket
		 */
		public function close():void 
		{
			if (socket != null)
				socket.close();
			__isConnecting = false;
		}
		
		
		/**
		 * Whenever the socket is connected, this function will be called
		 */
		protected function connectSuccess():void 
		{
			
		}
		
		/**
		 * Whenever the socket connect failed, this function will be called
		 * @param	flag	the type of the error
		 */
		protected function connectFailed(flag:int):void 
		{
			
		}
		
		/**
		 * Whenever the socket received data, this function will be called
		 */
		protected function connectReceive():void 
		{
			
		}
		
		
// =================================================================================================
//  event handlers
// =================================================================================================
		// the connction closed
		private function onClosed(e:Event):void 
		{
			connectFailed(DataSocket.FLAG_CLOSE);
		}
		
		// Connected Handler
		private function onConnected(e:Event):void 
		{
			__isConnecting = false;
			connectSuccess();
		}
		
		// IOError Handler
		private function onIOError(e:IOErrorEvent):void 
		{
			__isConnecting = false;
			connectFailed(DataSocket.FLAG_IOERROR);
		}	
		
		// SocketData Handler
		private function onSocketReceived(e:ProgressEvent):void 
		{
			connectReceive();
		}
		
		//	SecurityError Handler
		private function onSecurityError(e:Event):void 
		{
			__isConnecting = false;
			connectFailed(DataSocket.FLAG_SECURITYERROR);
		}
		
		
// =================================================================================================
//  getter/setter
// =================================================================================================
		/**
		 * Indicates the socket is connecting or not
		 */
		public function get isConnecting():Boolean { return __isConnecting; }
		
		/**
		 * Indicates the socket is connected or not
		 */
		public function get isConnected():Boolean
		{
			return (socket != null && socket.connected);
		}
	}

}